package com.liveinstars.account.business.service.impl;

import com.liveinstars.account.business.domain.bo.*;
import com.liveinstars.account.business.domain.vo.Account;
import com.liveinstars.account.business.exception.AccountExceptionEnum;
import com.liveinstars.account.business.mapper.AuthUserMapper;
import com.liveinstars.account.business.mapper.SocialQqMapper;
import com.liveinstars.account.business.mapper.SocialWechatMapper;
import com.liveinstars.account.business.mapper.SocialWeiboMapper;
import com.liveinstars.account.business.service.AccountService;
import com.liveinstars.account.business.service.UserService;
import com.liveinstars.account.business.util.CommonUtil;
import com.liveinstars.account.business.util.Md5Util;
import com.liveinstars.api.dto.*;
import com.onepiece.cache.service.CacheService;
import com.onepiece.shipelves.common.enums.SystemExceptionEnum;
import com.onepiece.shipelves.common.exception.QuHuiRuntimeException;
import com.onepiece.shipelves.common.utils.AESPKCS7Util;
import com.onepiece.shipelves.common.utils.JsonWebTokenUtil;
import com.onepiece.shipelves.common.utils.JwtAccount;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;

import static com.liveinstars.account.business.util.AesUtil.ENCODE_RULES;

/**
 * @author tomsun28
 * @date 22:04 2018/3/7
 */
@Service("AccountService")
public class AccountServiceImpl implements AccountService {

    private static final Logger logger = LoggerFactory.getLogger(ResourceServiceImpl.class);
    @Autowired
    private AuthUserMapper userMapper;

    @Autowired
    SocialQqMapper socialQqMapper;

    @Autowired
    SocialWechatMapper socialWechatMapper;

    @Autowired
    SocialWeiboMapper socialWeiboMapper;

    @Autowired
    private UserService userService;


    @Autowired
    CacheService cache;

    @Override
    public Account loadAccount(String appId) throws DataAccessException {
        User user = userMapper.selectByUniqueKey(appId);
        return user != null ? new Account(user.getUserName(), user.getPassword(), user.getSalt()) : null;
    }

    @Override
    public boolean isAccountExistByUserName(String uid) {
        User user = userMapper.selectByUserName(uid);
        return user != null ? Boolean.TRUE : Boolean.FALSE;
    }

    @Override
    public boolean registerAccount(User account) throws DataAccessException {

        // 给新用户授权访客角色
        userService.authorityUserRole(account.getUserName(), 103);

        return userMapper.insertSelective(account) == 1 ? Boolean.TRUE : Boolean.FALSE;
    }

    @Override
    public String loadAccountRole(String appId) throws DataAccessException {

        return userMapper.selectUserRoles(appId);
    }


    @Override
    public boolean validAccount(String userName, String password) {
        String realPassword = AESPKCS7Util.decrypt(password, ENCODE_RULES);
        if(StringUtils.isEmpty(realPassword)){
            return false;
        }
        User userByAppId = userService.getUserByAppId(userName);
        if(userByAppId != null){
            String md = Md5Util.md5(realPassword + userByAppId.getSalt());
            logger.info("validAccount realPassword={} {} {} {}", realPassword,userByAppId.getSalt(),md,userByAppId.getPassword());
            if(md.equals(userByAppId.getPassword())){
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean bindSocialAccount(String userName, String type, String unionid, String openid) {
        return false;
    }


    @Override
    public void loginByMobile(String mobile, String code) {

        validMobileCode(mobile, code);

        //获取用户，不存在创建用户，并返回true
        User user = userMapper.selectByMobile(mobile);
        if (user == null) {
            User authUser = new User();
            String salt = CommonUtil.getRandomString(6);
            String ramdom = CommonUtil.getRandomString(3);
            String substring = mobile.substring(3, 8);
            String replace = mobile.replace(substring, "*****");
            authUser.setUserName(replace + "手机用户" + ramdom);
            authUser.setNickName(authUser.getUserName());

            authUser.setCreateTime(new Date());
            authUser.setPhone(mobile);
            authUser.setStatus((byte) 1);
            // 存储到数据库的密码为 MD5(原密码+盐值)
            authUser.setPassword(Md5Util.md5(salt));

            if (registerAccount(authUser)) {

            } else {
                throw new QuHuiRuntimeException("500", "注册失败！");
            }
        }
    }

    @Override
    public String loginBySocial(String type, String unionid, String openid) {
        Integer userId = null;
        if(AccountEnum.QQ.getAccountMsg().equals(type)) {
            userId = qqLogin(unionid,openid);
        }else if(AccountEnum.WEIXIN.getAccountMsg().equals(type)) {
            userId = wechatLogin(unionid,openid);
        }else if(AccountEnum.WEIBO.getAccountMsg().equals(type)) {
            userId = weiboLogin(openid);
        }
        if(userId != null) {
            User user = userMapper.selectById(userId);
            if(user != null) {
                return user.getUserName();
            }
        }
        return "";
    }

    @Override
    public boolean validToken(String token, Long uid) {
        JwtAccount jwtAccount = null;
        try{
            jwtAccount = JsonWebTokenUtil.parseJwt(token,JsonWebTokenUtil.SECRET_KEY);
            return true;
        } catch(SignatureException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e){
            // 令牌错误
            logger.error("errJwt" +  token);
        } catch(ExpiredJwtException e){
            // 令牌过期
            logger.error("expiredJwt" + token);
        } catch(Exception e){
            logger.error("errJwt" + token);
        }
        if(null == jwtAccount){
            logger.error("errJwt" + token);
        }
        return false;
    }

    @Override
    public BindInfo loadBindInfo(Integer uid) {
        BindInfo bind_info = new BindInfo();
        SocialWechat socialWechat = getSocialWechatByUid(uid);
        if (socialWechat != null) {
            Weixin weixin = new Weixin();
            weixin.setOpenid(socialWechat.getOpenid());
            weixin.setUid(String.valueOf(uid));
            bind_info.setWeixin(weixin);
        }
        SocialWeibo socialWeibo = getSocialWeiboByUid(uid);
        if (socialWeibo != null) {
            BindInfoWeibo weibo = new BindInfoWeibo();
            weibo.setUid(String.valueOf(uid));
            weibo.setOpenid(String.valueOf(socialWeibo.getSinaUid()));
            weibo.setOpenid_web(String.valueOf(socialWeibo.getOpenidWeb()));
            weibo.setSina_username(socialWeibo.getSinaUsername());
            weibo.setUsername(socialWeibo.getUsername());
            bind_info.setWeibo(weibo);
        }
        SocialQq socialQq = getSocialQqByUid(uid);
        if (socialQq != null) {
            BindInfoQq qq = new BindInfoQq();
            qq.setUid(String.valueOf(uid));
            qq.setAvatar(socialQq.getPhoto());
            qq.setNickname(socialQq.getNickname());
            qq.setOpenid(socialQq.getOpenid());
            qq.setOpenid_web(socialQq.getOpenidWeb());
            qq.setUsername(socialQq.getUsername());
            bind_info.setQq(qq);
        }

        return bind_info;
    }

    @Override
    public UpdateUserpwdVO updateUserPasswordByUserName(UnifyAppUpdatepwdReq req) {
        logger.info("UnifyAuthenticateServiceImpl updateUserPasswordByUserName req={} ", req);

        Integer uid = req.getUid();
        User account = userMapper.selectById(uid);
        if (account == null) {
            throw new QuHuiRuntimeException(SystemExceptionEnum.UN_KNOW_ERROR);
        }

        String realPassword = AESPKCS7Util.decrypt(req.getPassword(), ENCODE_RULES);
                    String salt = account.getSalt();
                    // 存储到数据库的密码为 MD5(原密码+盐值)

        String oldPwd =  (Md5Util.md5(realPassword + salt));
        logger.info("UnifyAuthenticateServiceImpl updateUserPasswordByUserName realPassword={} {} {} {}", realPassword,salt,oldPwd,account.getPassword());
        if (!oldPwd.equals(account.getPassword())) {
            throw new QuHuiRuntimeException(SystemExceptionEnum.UN_KNOW_ERROR);
        }

        return updateUserPwd(req, account);
    }

    private UpdateUserpwdVO updateUserPwd(UnifyAppUpdatepwdReq req, User account) {
        logger.info("UnifyAuthenticateServiceImpl updateUserPwd req={} ", req);
        String newPassword = req.getNewpassword();
        UpdateUserpwdVO updateUserpwdVO = new UpdateUserpwdVO();
        updateUserpwdVO.setStatus("fail");
        updateUserpwdVO.setUid(req.getUid());
        try {
            // 加密方式
            String realPassword = AESPKCS7Util.decrypt(newPassword, ENCODE_RULES);
            String salt = CommonUtil.getRandomString(6);
            String pwd = Md5Util.md5(realPassword + salt);
            account.setPassword(pwd);
            account.setSalt(salt);
            account.setUpdateTime(new Date());
            int result = userMapper.updateByPrimaryKey(account);
            if (result > 0) {
                logger.info("UnifyAuthenticateServiceImpl updateUserPwd {} {}", salt, pwd);
                updateUserpwdVO.setStatus("success");
            }
        } catch (Exception e) {
            logger.error("UnifyAuthenticateServiceImpl updateUserPwd req={} ", req, e);
        }
        return updateUserpwdVO;
    }

    @Override
    public UpdateUserpwdVO updateUserPasswordByMobile(UnifyAppUpdatepwdReq req) {
        logger.info("UnifyAuthenticateServiceImpl updateUserPasswordByMobile req={} ", req);
        String mobile = req.getMobile();
        String code = req.getCode();

        User account = userMapper.selectByMobile(mobile);
        if (account == null) {
            throw new QuHuiRuntimeException(SystemExceptionEnum.UN_KNOW_ERROR);
        }
        String key = String.format("sms_login_%s", mobile);
        if (StringUtils.isEmpty(code)) {
            throw new QuHuiRuntimeException("500", "验证码为空");
        }
        if (!cache.exists(key)) {
            throw new QuHuiRuntimeException("500", "验证码已失效");
        }
        if (!code.equals(cache.get(key))) {
            throw new QuHuiRuntimeException("500", "验证码错误");
        }
        return updateUserPwd(req, account);
    }

    @Override
    public boolean validMobileCode(String mobile, String code) {
        String key = String.format("sms_login_%s", mobile);
        if (StringUtils.isEmpty(code)) {
            throw new QuHuiRuntimeException("500", "验证码为空");
        }
        if (!cache.exists(key)) {
            throw new QuHuiRuntimeException("500", "验证码已失效");
        }
        if (!code.equals(cache.get(key))) {
            throw new QuHuiRuntimeException("500", "验证码错误");
        }
        return true;
    }

    @Override
    public boolean bindMobile(String userName, String mobile) {
        User account = userMapper.selectByMobile(mobile);
        if(account != null){
            throw new QuHuiRuntimeException(AccountExceptionEnum.MOBILE_EXIST);
        }
        account = userMapper.selectByUserName(userName);
        if (account == null) {
            throw new QuHuiRuntimeException(AccountExceptionEnum.ENTITY_NOT_FOUND);
        }
        account.setPhone(mobile);

        int result = userMapper.updateByPrimaryKey(account);
        return result > 0;
    }

    public SocialWechat getSocialWechatByUid(Integer uid) {
        if (uid == null || uid == 0) {
            throw SystemExceptionEnum.ILLEGAL_REQUEST_PARAM.ex;
        }
        SocialWechatExample example = new SocialWechatExample();
        example.createCriteria().andUidEqualTo(uid.intValue());
        List<SocialWechat> wechats = socialWechatMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(wechats)) {
            return wechats.get(0);
        }
        return null;
    }

    public SocialWeibo getSocialWeiboByUid(Integer uid) {
        if (uid == null || uid == 0) {
            throw SystemExceptionEnum.ILLEGAL_REQUEST_PARAM.ex;
        }
        return socialWeiboMapper.selectByPrimaryKey(uid.intValue());
    }

    public SocialQq getSocialQqByUid(Integer uid) {
        if (uid == null || uid == 0) {
            throw SystemExceptionEnum.ILLEGAL_REQUEST_PARAM.ex;
        }
        return socialQqMapper.selectByPrimaryKey(uid.intValue());
    }

    private void weiboRegister(Integer uid) {
        SocialWeibo socialWeibo = new SocialWeibo();
        socialWeibo.setUid(uid);
        insertSocialWeibo(socialWeibo);
    }

    private int insertSocialWeibo(SocialWeibo socialWeibo) {
        return socialWeiboMapper.insert(socialWeibo);
    }

    private void wechatRegister(Integer uid) {
        SocialWechat socialWechat = new SocialWechat();
        socialWechat.setUid(uid);
        insertSocialWechat(socialWechat);
    }

    private int insertSocialWechat(SocialWechat socialWechat) {
        return socialWechatMapper.insert(socialWechat);
    }

    private void qqRegister(Integer uid) {
        SocialQq socialQq = new SocialQq();
        socialQq.setUid(Long.valueOf(uid));
        insertSocialQq(socialQq);
    }

    private int insertSocialQq(SocialQq socialQq) {
        return socialQqMapper.insert(socialQq);
    }

    private Integer weiboLogin(String openid) {
        List<SocialWeibo> weiboList = getSocialWeiboBySuid(openid);
        if(weiboList.size()>0&&!weiboList.isEmpty()) {
            SocialWeibo weibo = weiboList.get(0);
            return weibo.getUid();
        }

        return null;
    }

    private List<SocialWeibo> getSocialWeiboBySuid(String openid) {
        SocialWeiboExample socialWeiboExample = new SocialWeiboExample();
        socialWeiboExample.createCriteria().andSinaUidEqualTo(Long.valueOf(openid));
        return socialWeiboMapper.selectByExample(socialWeiboExample);
    }

    private Integer wechatLogin(String unionid, String openid) {
        //先根据unionid去查
        List<SocialWechat> weList = getSocialWechatByUnioinid(unionid);
        if(weList.size()>0&&!weList.isEmpty()) {
            for(SocialWechat socialWechat:weList) {
                if(openid.equals(socialWechat.getOpenid())) {
                    //有相同openid返回
                    return socialWechat.getUid();
                }
            }
        }

        SocialWechat wechat = getSocialWechatByOpenid(openid);
        if(null != wechat) {
            return wechat.getUid();
        }

        return null;
    }

    private SocialWechat getSocialWechatByOpenid(String openid) {
        SocialWechatExample socialWechatExample = new SocialWechatExample();
        socialWechatExample.createCriteria().andOpenidEqualTo(openid);
        List<SocialWechat> wechatList = socialWechatMapper.selectByExample(socialWechatExample);
        if (wechatList.size() > 0 && !wechatList.isEmpty()) {
            return wechatList.get(0);
        }
        return null;
    }

    private List<SocialWechat> getSocialWechatByUnioinid(String unionid) {
        SocialWechatExample socialWechatExample = new SocialWechatExample();
        socialWechatExample.createCriteria().andUnionidEqualTo(unionid);
        return socialWechatMapper.selectByExample(socialWechatExample);
    }

    private Integer qqLogin(String unionid,String openid) {
        //先根据unionid去查
        List<SocialQq> qqList = getSocialQqByUnioinid(unionid);

        if(qqList.size()>0&&!qqList.isEmpty()) {
            for(SocialQq socialQq:qqList) {
                if(openid.equals(socialQq.getOpenid())) {
                    //有相同openid返回
                    return Math.toIntExact(socialQq.getUid());
                }
            }
        }

        SocialQq openQq = getSocialQqByOpenid(openid);
        if(null != openQq) {
            return Math.toIntExact(openQq.getUid());
        }

        return null;
    }

    private SocialQq getSocialQqByOpenid(String openid) {
        SocialQqExample socialQqExample = new SocialQqExample();
        socialQqExample.createCriteria().andOpenidEqualTo(openid);
        List<SocialQq> qqLsit = socialQqMapper.selectByExample(socialQqExample);
        if (qqLsit.size() > 0 && !qqLsit.isEmpty()) {
            return qqLsit.get(0);
        }
        return null;
    }

    private List<SocialQq> getSocialQqByUnioinid(String unionid) {
        SocialQqExample socialQqExample = new SocialQqExample();
        socialQqExample.createCriteria().andUnionidEqualTo(unionid);
        return socialQqMapper.selectByExample(socialQqExample);
    }

}
